Skip to content

text: Preserve logical selection across presentation changes - #3421

Merged
huacnlee merged 4 commits into
longbridge:mainfrom
TomiXRM:fix/kagi-compatible-selection
Oct 9, 2026
Merged

huacnlee merged 4 commits into
longbridge:mainfrom
TomiXRM:fix/kagi-compatible-selection

Conversation

@TomiXRM

@TomiXRM TomiXRM commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Description

Completed partial selections in a managed TextViewState should survive presentation changes when the source is unchanged. This PR retains the logical selection range and Copy payload across style, syntax-highlighter, inherited-font, zoom, and width changes by default. It adds no configuration API.

Current styles and wrapping still apply. The retained range is not reconstructed by projecting an old pointer rectangle onto the new layout, and later outer-layout origin changes do not become new selection gestures. A new drag or explicit clear updates selection normally. Source replacement and Markdown parser-configuration replacement still invalidate selection.

The owning view must retain both the state and its painted selection participant. This behavior does not pin rows unmounted by an outer virtual list. Changes are confined to SDK selection policy; GPUI and platform input are not patched. The changes were developed with AI assistance.

Motivation: Kagi issue #1091. This PR addresses selection behavior and does not claim to complete the broader conversation-performance work.

Public API

No public APIs are added, removed, or changed relative to the base branch. The opt-in builder proposed in earlier revisions has been removed; presentation-only changes now preserve completed selections by default.

Validation

Validated locally after commit 48cc5389a:

  • 331 Base and 69 Component tests selected by text::: all 400 passed.
  • 7 Kit text-selection integration tests: all passed. Fixtures use gpui_kit::open_window through the shared test helper.
  • cargo fmt --all --check: passed.
  • Clippy for Base, Component, Kit, and the text-selection integration target with --deny warnings: passed.
  • git diff --check: passed.

Coverage includes completed partial selection and Copy across color, width-only, font, zoom, and origin changes; cross-block and cross-renderer reflow; new drags replacing retained ranges; explicit clear; source replacement; and parser-configuration replacement. Syntax-highlighter changes apply new presentation while preserving the selection. The existing Component regression now verifies default retention after same-size style changes.

The Base README and English/Chinese TextView documentation describe the default behavior and mounted-participant requirement. Native GUI/performance evaluation has not been performed for this update. Results from CI on earlier revisions do not validate the latest head.

@TomiXRM
TomiXRM marked this pull request as draft October 8, 2026 17:19
@TomiXRM

TomiXRM commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

追加の静的レビューで、幅のみの変更と、その後のスクロールにおける論理選択保持に2件のリスクが見つかりました。既存1969件の通過だけではこの境界を保証できないため draft に戻しました。再現ケースを追加し、通常の追加commitで修正・再検証します。現在のheadを完成済みとは扱いません。

@TomiXRM

TomiXRM commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

追加commit 6c783a2 で2件を修正しました。幅単独の実リフロー、およびfont+width更新後の外側origin移動を、実ドラッグ・論理source range・Copy dispatch・複数paint・新規dragの回帰で検証しています。gpui-base/component test-support全1970件、fmt、Clippy通過。追加commitの静的再レビューでも先の2件の解消を確認しました。既定falseとsource/parser無効化は維持します。これらは公開headの検証で、main統合後のbuild/testは上流CIの結果を別途確認します。

@TomiXRM
TomiXRM marked this pull request as ready for review October 8, 2026 17:40
@huacnlee huacnlee changed the title feat(text): スタイル変更時の論理選択保持をオプトインで追加 text: Preserve logical selection across presentation changes with an opt-in Oct 9, 2026
@huacnlee huacnlee changed the title text: Preserve logical selection across presentation changes with an opt-in text: Preserve logical selection across presentation changes Oct 9, 2026
@huacnlee
huacnlee enabled auto-merge (squash) October 9, 2026 13:41
@huacnlee
huacnlee merged commit 0bbd987 into longbridge:main Oct 9, 2026
16 checks passed
@huacnlee huacnlee mentioned this pull request Oct 12, 2026
huacnlee added a commit that referenced this pull request Oct 12, 2026
## Description

Prepare v0.7.2 on `stable` from the PRs merged into `main` since v0.7.1,
leaving out every change that breaks existing consumers. `stable`
already carries #3371 and #3373; this adds the remaining compatible PRs
with `git cherry-pick -x` and bumps the workspace to 0.7.2.

### Included

- kit: Add optional gpui-fast backend (#3375)
- tooltip: Make show delay and grace period configurable with
`TooltipDefaults` (#3376)
- docs: Explain recovering focus when the focused element stops
rendering (#3386)
- diff: Add readonly patch viewer (#3378)
- kit: Use one Windows manifest with GPUI Fast (#3380)
- test: Make Progress and TitleBar findable in UI tests (#3383)
- input: Preserve selection, focus ring and context menu actions (#3382)
- diff: Add a Git history example and complete review APIs (#3388)
- text_view: Ignore gestures that stay inside one block plugin (#3390)
- text_view: Round the first and last table rows to the frame radius
(#3309)
- menu: Open a context menu with a long press on touch (#3393)
- text_view: Keep narrow table columns on one line (#3399)
- settings: Keep focus rings inside the list viewport (#3394)
- scrollable_mask: Keep rounded scroll-table corners clean at any scroll
offset (#3400)
- dialog: Add margin_top to AlertDialog (#3404)
- input: Add InputState::add_selection for programmatic multi-cursor
(#3403)
- text_selection: Stop writing selection state on every frame (#3407)
- table: Make the sort icon a labelled button (#3396)
- table: Report visible row ranges of one row or none (#3397)
- dialog: Support configurable entrance animations (#3405)
- docs: Explain the open_dialog builder and footer contracts (#3406)
- dock: Hand the focus to the tab that replaces a closed one (#3409)
- dropdown_button: Add A11y names for the menu trigger (#3410)
- text, resizable: Stop notifying state that did not change (#3418)
- editor: Add on-demand completion commands (#3411)
- table: Clear a right-clicked cell's outline on the next click (#3413)
- tab: Scroll a clicked tab into view with the next one peeking (#3419)
- table: Allow a header row height separate from the body (#3420)
- menu: Focus a context menu before its first frame (#3422)
- text: Preserve logical selection across presentation changes (#3421)
- text: Keep inline HTML mark highlights in Markdown (#3425)
- input: Anchor completion/code-action popups to the current frame's
caret (#3412)
- input: Run custom context menu builders after releasing the input
(#3433)
- input: Keep auto-grow rows fitted when the limits change (#3430)
- text: Paint TextView selection under the glyphs (#3439)

Already on `stable`: #3371, #3373.

### Excluded (Breaking Changes)

- #3432 motion: `Easing::sample` now returns values outside `[0, 1]` for
overshooting curves.
- #3415 tab: new `TabVariant::Folder` breaks exhaustive matches.
- #3402 kit: pointer helpers now keep held modifiers; nested
context-menu behavior changes in tests.
- #3384 test: `TestWindowExt` gains required methods.
- #3302 resizable: `ResizeHandle::on_drag` takes `&T` instead of
`Rc<T>`.
- #3389, #3395, #3398 webview: wrapper API changes, `gpui-wry` →
`gpui-webview` rename, and the GPUI Fast requirement.

#3411, #3405 and #3396 have a Breaking Changes section that reads "None"
and are included. #3376 only deprecates `TooltipRequest::placement`, and
#3397 / #3382 change behavior compatibly, so they are included too.

### Adaptations

- `crates/kit/tests/collections.rs` and `crates/kit/tests/rendering.rs`:
conflict resolutions drop the tests that belong to #3402 and keep each
backported PR's own test.
- `test: Keep backported tests on the v0.7.1 test API`: the menu and
completion tests from #3422 and #3412 used `find_all` and
`pointer_down`/`pointer_up` from #3384/#3402. They now query
`gpui_kit::base::test_support::snapshots` and dispatch mouse events
directly.
- `kit: Prepare v0.7.2`: workspace version bump; `Cargo.lock` only
updates workspace members.

## Public API

No new public API beyond what the included PRs add; each lists its items
in its own `## Public API` section (notably #3375, #3376, #3378, #3388,
#3403, #3404, #3405, #3411, #3420).

## How to Test

- `cargo clippy --workspace --all-targets -- --deny warnings` passes on
Linux.
- `cargo test -p gpui-kit --features "test-support component assets"
--test collections --test menu --test input` passes on Linux.
- The macOS-only `rendering` test (#3439 adds one case, the count is
updated to 11) was not run.

AI-assisted: the backport, conflict resolution and test adaptations were
done with Claude Code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Floyd Wang <codelife721@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Gustave <gustavel@gmail.com>
Co-authored-by: luren <84951845+lurenjia534@users.noreply.github.com>
Co-authored-by: Ylin <ylinwind@gmail.com>
Co-authored-by: ihavecoke <mixboip@gmail.com>
Co-authored-by: Lorenzo <150276837+Bombatomica64@users.noreply.github.com>
Co-authored-by: MR. XIE <113512030+xxww0098@users.noreply.github.com>
Co-authored-by: xxww0098 <shefkie1957@gmail.com>
Co-authored-by: Sola 🌙🤖 <266175376+sola-ryu@users.noreply.github.com>
Co-authored-by: Sola <sola-ryu@users.noreply.github.com>
Co-authored-by: Andy Hsu <i@nn.ci>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Floyd Wang <gassnake999@gmail.com>
Co-authored-by: Daiki Tomioka <20753105+TomiXRM@users.noreply.github.com>
Co-authored-by: Henrik Øgård <henrik@ogard.no>
Co-authored-by: Henrik Øgård <henrikogaard@users.noreply.github.com>
Co-authored-by: Endless <endless@longbridge.com>
Co-authored-by: John Costa <costajohnt@gmail.com>
Co-authored-by: Alexander <87220898+sneffets@users.noreply.github.com>
Co-authored-by: Cesar Talén <154442565+cesartalen@users.noreply.github.com>
trancong12102 added a commit to aislopware/gpui-kit that referenced this pull request Oct 12, 2026
longbridge#3421 keeps a finished selection's logical range across a
style, highlighter, font or width change and stopped moving the
selection revision for a new style. The fork's e3ae5ff rewrote the
block that hands the element's inputs to the state, and replaying it
over longbridge#3421 brought the revision bump back: a style change cleared the
selection, failing longbridge#3421's kit text_selection tests and the
component's same_size_style_reflow_keeps_finished_selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
trancong12102 added a commit to aislopware/gpui-kit that referenced this pull request Oct 13, 2026
longbridge#3421 keeps a finished selection's logical range across a
style, highlighter, font or width change and stopped moving the
selection revision for a new style. The fork's e3ae5ff rewrote the
block that hands the element's inputs to the state, and replaying it
over longbridge#3421 brought the revision bump back: a style change cleared the
selection, failing longbridge#3421's kit text_selection tests and the
component's same_size_style_reflow_keeps_finished_selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants